﻿//========================================================= 
/**@file Game2048.h
 * @brief 2048游戏逻辑
 * 
 * @date 2017-09-26   10:19:18
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_GAME2048_H_
#define _LIBZHOUYB_GAME2048_H_
//--------------------------------------------------------- 
#include <iostream>

#include "../../include/Base.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace game {
//--------------------------------------------------------- 
class Game2048
{
protected:
    enum MoveMode
    {
        Nothing,
        OnlyMove,
        MoveAndFold
    };

    typedef MoveMode(Game2048::*fpMove)(uint);

    uint Depth;
    uint _block[5][5];
    uint _cache[5];
    list_t<std::pair<uint, uint> > _space;

    static bool ArrToLeft(uint arr[], uint depth)
    {
        uint index = 0;
        bool isMove = false;
        for(uint i = 1;i < depth; ++i)
        {
            if(arr[index] != 0)
            {
                ++index;
                continue;
            }
            
            if(arr[i] != 0)
            {
                arr[index] = arr[i];
                arr[i] = 0;
                ++index;
                isMove = true;
            }
        }
        return isMove;
    }
    static bool ArrToFold(uint arr[], uint depth)
    {
        uint index = 0;
        bool isFold = false;
        for(uint i = 1;i < depth; ++i)
        {
            if((arr[i - 1] == arr[i]) && (arr[i - 1] != 0))
            {
                arr[i - 1] += arr[i];
                for(uint j = i;j < depth - 1; ++j)
                {
                    arr[j] = arr[j + 1];
                    arr[j + 1] = 0;
                }
                isFold = true;
                break;
            }
        }
        return isFold;
    }

    MoveMode ToMode(bool isMove, bool isFold)
    {
        if(!isMove && !isFold)
            return Nothing;
        if(isMove && !isFold)
            return OnlyMove;
        return MoveAndFold;
    }
    size_t ToScan()
    {
        size_t count = 0;
        _space.clear();
        for(uint i = 0;i < Depth; ++i)
        {
            for(uint j = 0;j < Depth; ++j)
            {
                if(_block[i][j] == 0)
                {
                    _space.push_back(std::make_pair(i, j));
                    ++count;
                }
            }
        }
        return count;
    }
    MoveMode ToLeft(uint row)
    {
        bool isMove = ArrToLeft(_block[row], Depth);
        bool isFold = ArrToFold(_block[row], Depth);
        return ToMode(isMove, isFold);
    }
    MoveMode ToTop(uint col)
    {
        for(uint i = 0;i < Depth; ++i)
        {
            _cache[i] = _block[i][col];
        }
        bool isMove = ArrToLeft(_cache, Depth);
        bool isFold = ArrToFold(_cache, Depth);
        for(uint i = 0;i < Depth; ++i)
        {
            _block[i][col] = _cache[i];
        }
        return ToMode(isMove, isFold);
    }
    MoveMode ToBottom(uint col)
    {
        for(uint i = 0;i < Depth; ++i)
        {
            _cache[i] = _block[Depth - i - 1][col];
        }
        bool isMove = ArrToLeft(_cache, Depth);
        bool isFold = ArrToFold(_cache, Depth);
        for(uint i = 0;i < Depth; ++i)
        {
            _block[Depth - i - 1][col] = _cache[i];
        }
        return ToMode(isMove, isFold);
    }
    MoveMode ToRight(uint row)
    {
        for(uint i = 0;i < Depth; ++i)
        {
            _cache[i] = _block[row][Depth - i - 1];
        }
        bool isMove = ArrToLeft(_cache, Depth);
        bool isFold = ArrToFold(_cache, Depth);
        for(uint i = 0;i < Depth; ++i)
        {
            _block[row][Depth - i - 1] = _cache[i];
        }
        return ToMode(isMove, isFold);
    }
    size_t MoveTo(fpMove func)
    {
        size_t count = 0;
        size_t nothingCount = 0;
        for(uint i = 0;i < Depth; ++i)
        {
            MoveMode mode = (this->*func)(i);
            switch(mode)
            {
            case MoveAndFold:
                ++count;
                break;
            case Nothing:
                ++nothingCount;
                break;
            }
        }
        if(nothingCount >= Depth)
            return SIZE_EOF;

        ToScan();
        return count;
    }
public:
    Game2048()
    {
        Depth = 5;

        Reset();
    }
    void Reset()
    {
        _space.clear();
        for(uint i = 0;i < Depth; ++i)
        {
            for(uint j = 0;j < Depth; ++j)
            {
                _block[i][j] = 0;
                _space.push_back(std::make_pair(i, j));
            }
        }
    }
    bool CanMove()
    {
        int depth = static_cast<int>(Depth);
        for(int i = 0;i < depth; ++i)
        {
            for(int j = 0;j < depth; ++j)
            {
                // 有效点
                if(_block[i][j] == 0)
                    continue;
                int k = 0;
                // 上
                for(k = i - 1;k >= 0; --k)
                {
                    if(_block[k][j] == 0)
                        continue;
                    if(_block[i][j] == _block[k][j])
                        return true;
                    break;
                }
                // 下
                for(k = i + 1;k < depth; ++k)
                {
                    if(_block[k][j] == 0)
                        continue;
                    if(_block[i][j] == _block[k][j])
                        return true;
                    break;
                }
                // 左
                for(k = j - 1;k >= 0; --k)
                {
                    if(_block[i][k] == 0)
                        continue;
                    if(_block[i][j] == _block[i][k])
                        return true;
                    break;
                }
                // 右
                for(k = j + 1;k < depth; ++k)
                {
                    if(_block[i][k] == 0)
                        continue;
                    if(_block[i][j] == _block[i][k])
                        return true;
                    break;
                }
            }
        }
        return false;
    }
    bool Random()
    {
        size_t count = _space.size();
        if(count < 1)
            return false;
        size_t index = rand() % count;
        list_t<std::pair<uint, uint> >::iterator itr = list_helper<std::pair<uint, uint> >::index_of(_space, index);
        _block[itr->first][itr->second] = 2;
        _space.erase(itr);
        return true;
    }
    inline size_t MoveLeft()
    {
        return MoveTo(&Game2048::ToLeft);
    }
    inline size_t MoveTop()
    {
        return MoveTo(&Game2048::ToTop);
    }
    inline size_t MoveRight()
    {
        return MoveTo(&Game2048::ToRight);
    }
    inline size_t MoveBottom()
    {
        return MoveTo(&Game2048::ToBottom);
    }
    void Print(LoggerAdapter& _log)
    {
        for(uint i = 0;i < Depth; ++i)
        {
            for(uint j = 0;j < Depth; ++j)
            {
                _log << _left_width(_block[i][j], 5);
            }
            _log.WriteLine();
        }
    }
};
//--------------------------------------------------------- 
} // nemespace game
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_GAME2048_H_
//========================================================= 